/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package model;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.EnumMap;
import javax.imageio.ImageIO;
import model.Game.Difficulties;
import model.LevelInterpreter.Parts;

/**
 * LevelSpecification de specificatie klasse van een level.
 * Een LevelSpecificatie object wordt door de levelInterperter oververtaald naar een level.
 * De LevelSpecificatie klasse kan worden geserializeerd.
 */
public class LevelSpecification implements Serializable {

    private EnumMap<Parts, byte[]> partAppearance;
    private int[][] fieldSpecification;
    private ArrayList<String> msg;
    private String name;
    private Difficulties difficulty;

    public LevelSpecification() {
        this.msg = new ArrayList<>();
        this.partAppearance = new EnumMap<>(Parts.class);
        this.difficulty = Difficulties.EASY;
    }

    /**
     * @return the fieldSpecification
     */
    public int[][] getFieldSpecification() {
        return fieldSpecification;
    }

    /**
     * @param fieldSpecification the fieldSpecification to set
     */
    public void setFieldSpecification(int[][] fieldSpecification) {
        this.fieldSpecification = fieldSpecification;
    }
    
    /*
     * Deze methode slaat een BufferedImage op in PartAppereance.
     * Invoer : het part waarvan de afbeelding een afspiegeling is en de afbeelding zelf.
     * Uitvoer: true als het gelukt is anders false.
     * Een afbeelding wordt oververtaald naar een byteArray gaat er iets fout bij de overvetaling
     * dan zal de functie een bericht wegschrijven naar het msgArray en false retouneren. Anders
     * slaat hij de afbeelding op in partAppearence.
     */
    public boolean setImage(Parts part, BufferedImage image) {
        try {
            byte[] imageInByte;
            try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                ImageIO.write(image, "gif", baos);
                baos.flush();
                imageInByte = baos.toByteArray();
            }
            this.partAppearance.put(part, imageInByte);
        } catch (IOException ex) {
            this.getMsg().add("Het is niet gelukt de foto opteslaan: " + ex);
            return false;
        }
        return true;
    }
    
    
     /*
     * Deze methode haalt een BufferedImage op uit partAppereance.
     * Invoer : de part sleutel.
     * Uitvoer: een BufferedImage of null.
     * ALs er een byteArray aanwezig is wordt deze oververtaald naar een BufferedImage en geretourneert 
     * zoniet dat word null geretourneerd.
     */
    public BufferedImage getImage(Parts part) {
        if (this.partAppearance.get(part) != null) {
            ByteArrayInputStream in = new ByteArrayInputStream(this.partAppearance.get(part));
            try {
                BufferedImage image = ImageIO.read(in);
                return image;
            } catch (IOException ex) {
            }
        }
        return null;
    }

    public boolean imageExists(Parts part) {
        if (this.partAppearance.get(part) != null) {
            return true;
        }
        return false;
    }
    
    /*
     * Deze methode kijkt of de LevelSpecificatie wel voldoed aan de minimale eisen om geinterpreteerd teworden.
     * Invoer : niets.
     * Uitvoer: true als er geen fouten zijn geconstateerd zijn anders false.
     * De klasse vairabelen worden gevalideerd. Voor elke fout die hij tegenkomt schrijft hij een bericht weg in het msgArray.
     */
    public boolean validate() {

        boolean valid = true;
        if (this.partAppearance.get(Parts.BOX) == null) {
            this.getMsg().add("BOX plaatje is niet aanwezig");
            valid = false;
        } if (this.partAppearance.get(Parts.ENEMY) == null) {
            this.getMsg().add("ENEMY plaatje is niet aanwezig");
            valid = false;
        } if (this.partAppearance.get(Parts.WALL) == null) {
            this.getMsg().add("WALL plaatje is niet aanwezig");
            valid = false;
        } if (this.partAppearance.get(Parts.PLAYER) == null) {
            this.getMsg().add("PLAYER plaatje is niet aanwezig");
            valid = false;
        }

        if (this.fieldSpecification == null) {
            this.getMsg().add("Er is geen level aanwezig");
            valid = false;
            
        } else {

            int box = 0;
            int player = 0;
            int enemy = 0;
            int wall = 0;

            for (int row = 0; row < fieldSpecification.length; row++) {
                for (int column = 0; column < fieldSpecification[row].length; column++) {
                    switch (fieldSpecification[row][column]) {
                        case 0:
                            break;
                        case 1:
                            break;
                        case 2:
                            wall++;
                            break;
                        case 3:
                            box++;
                            break;
                        case 4:
                            enemy++;
                            break;
                        case 5:
                            player++;
                            break;
                    }
                }
            }

            if (box < 4) {
                this.getMsg().add("Er moeten minimaal 4 BOX zitten op een speelveld");
                valid = false;
            }

            if (enemy != 1) {
                this.getMsg().add("Er moet 1 ENEMY zijn");
                valid = false;
            }

            if (player != 1) {
                this.getMsg().add("Er moet 1 PLAYER zijn");
                valid = false;
            }
        }

        return valid;
    }

    /**
     * @return the msg
     */
    public ArrayList<String> getMsg() {
        return msg;
    }

    public void clearMsg() {
        msg = new ArrayList<>();
    }

    /**
     * @return the name
     */
    public String getName() {
        return name;
    }

    /**
     * @param name the name to set
     */
    public void setName(String name) {
        this.name = name;
    }

    /**
     * @return the difficulty
     */
    public Difficulties getDifficulty() {
        return difficulty;
    }

    /**
     * @param difficulty the difficulty to set
     */
    public void setDifficulty(Difficulties difficulty) {
        this.difficulty = difficulty;
    }
}
